<template>
  <div class="file-upload">
    <div class="file-upload-container" @click="onClickUpload" v-bind="$attrs">
      <slot name="loading" v-if="fileStatus === 'loading'">
        <button class="btn btn-primary" disabled>正在上传...</button>
      </slot>
      <slot name="uploaded" v-else-if="fileStatus === 'success'">
        <button class="btn btn-primary">上传成功</button>
      </slot>
      <slot name="default" v-else>
        <button class="btn btn-primary">点击上传</button>
      </slot>
    </div>
    <input
      type="file"
      @change="onFileChange"
      class="file-input d-none"
      ref="fileInput"
    />
  </div>
</template>

<script lang="ts">
import { useHttpErrorHandler } from "@/hooks";
import { useStore } from "@/store";
import { defineComponent, PropType, ref } from "vue";
import { useRouter } from "vue-router";
type UploadStatus = "ready" | "loading" | "success" | "error";
type CheckFunction = (file: File) => boolean | string;

export default defineComponent({
  props: {
    action: {
      type: String,
      required: true,
    },
    beforeUpload: {
      type: Function as PropType<CheckFunction>,
    },
  },
  emits: ["uploaded", "upload-failed"],
  inheritAttrs: false,
  setup(props, { emit }) {
    const fileInput = ref<HTMLInputElement | null>(null);
    const fileStatus = ref<UploadStatus>("ready");
    const router = useRouter();
    const store = useStore();
    const { handleError, handleResponse } = useHttpErrorHandler(
      router,
      store.commit
    );
    const onClickUpload = () => {
      if (fileInput.value) {
        fileInput.value.click();
      }
    };
    const onFileChange = (ev: Event) => {
      const target = ev.target as HTMLInputElement;
      if (target.files) {
        if (props.beforeUpload) {
          const result = props.beforeUpload(target.files[0]);

          if (typeof result === "string" || result === false) {
            return result ? alert(result) : result;
          }
        }

        fileStatus.value = "loading";
        const formData = new FormData();
        formData.append("file", target.files[0]);
        fetch(props.action, {
          method: "post",
          body: formData,
          // 不要手动设置，formData会自动设置 content-type和boundary
          headers: {
            // "Content-Type":"multipart/form-data"
            Authorization: `Bearer ${sessionStorage.getItem("token")}`,
          },
        })
          .then((res) => handleResponse(res))
          .then((res) => {
            if (res.code === 0) {
              fileStatus.value = "success";
              emit("uploaded", res.data);
            } else {
              fileStatus.value = "error";
              emit("upload-failed", res);
            }
          })
          .catch((err) => {
            fileStatus.value = "error";
            emit("upload-failed", err);
            handleError(err);
          })
          .finally(() => {
            if (fileInput.value) {
              fileInput.value.value = "";
            }
          });
      }
    };
    return {
      fileInput,
      fileStatus,
      onClickUpload,
      onFileChange,
    };
  },
});
</script>
